home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / couchdb / view.py < prev   
Text File  |  2009-08-19  |  7KB  |  225 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2007-2008 Christopher Lenz
  4. # All rights reserved.
  5. #
  6. # This software is licensed as described in the file COPYING, which
  7. # you should have received as part of this distribution.
  8.  
  9. """Implementation of a view server for functions written in Python."""
  10.  
  11. from codecs import BOM_UTF8
  12. import logging
  13. import os
  14. import sys
  15. import traceback
  16. from types import FunctionType
  17.  
  18. from couchdb import json
  19.  
  20. __all__ = ['main', 'run']
  21. __docformat__ = 'restructuredtext en'
  22.  
  23. log = logging.getLogger('couchdb.view')
  24.  
  25.  
  26. def run(input=sys.stdin, output=sys.stdout):
  27.     r"""CouchDB view function handler implementation for Python.
  28.  
  29.     :param input: the readable file-like object to read input from
  30.     :param output: the writable file-like object to write output to
  31.     """
  32.     functions = []
  33.  
  34.     def _log(message):
  35.         if not isinstance(message, basestring):
  36.             message = json.encode(message)
  37.         output.write(json.encode({'log': message}))
  38.         output.write('\n')
  39.         output.flush()
  40.  
  41.     def reset(config=None):
  42.         del functions[:]
  43.         return True
  44.  
  45.     def add_fun(string):
  46.         string = BOM_UTF8 + string.encode('utf-8')
  47.         globals_ = {}
  48.         try:
  49.             exec string in {'log': _log}, globals_
  50.         except Exception, e:
  51.             return {'error': {
  52.                 'id': 'map_compilation_error',
  53.                 'reason': e.args[0]
  54.             }}
  55.         err = {'error': {
  56.             'id': 'map_compilation_error',
  57.             'reason': 'string must eval to a function '
  58.                       '(ex: "def(doc): return 1")'
  59.         }}
  60.         if len(globals_) != 1:
  61.             return err
  62.         function = globals_.values()[0]
  63.         if type(function) is not FunctionType:
  64.             return err
  65.         functions.append(function)
  66.         return True
  67.  
  68.     def map_doc(doc):
  69.         results = []
  70.         for function in functions:
  71.             try:
  72.                 results.append([[key, value] for key, value in function(doc)])
  73.             except Exception, e:
  74.                 log.error('runtime error in map function: %s', e,
  75.                           exc_info=True)
  76.                 results.append([])
  77.                 _log(traceback.format_exc())
  78.         return results
  79.  
  80.     def reduce(*cmd, **kwargs):
  81.         code = BOM_UTF8 + cmd[0][0].encode('utf-8')
  82.         args = cmd[1:][0]
  83.         globals_ = {}
  84.         try:
  85.             exec code in {'log': _log}, globals_
  86.         except Exception, e:
  87.             log.error('runtime error in reduce function: %s', e,
  88.                       exc_info=True)
  89.             return {'error': {
  90.                 'id': 'reduce_compilation_error',
  91.                 'reason': e.args[0]
  92.             }}
  93.         err = {'error': {
  94.             'id': 'reduce_compilation_error',
  95.             'reason': 'string must eval to a function '
  96.                       '(ex: "def(keys, values): return 1")'
  97.         }}
  98.         if len(globals_) != 1:
  99.             return err
  100.         function = globals_.values()[0]
  101.         if type(function) is not FunctionType:
  102.             return err
  103.  
  104.         rereduce = kwargs.get('rereduce', False)
  105.         results = []
  106.         if rereduce:
  107.             keys = None
  108.             vals = args
  109.         else:
  110.             keys, vals = zip(*args)
  111.         if function.func_code.co_argcount == 3:
  112.             results = function(keys, vals, rereduce)
  113.         else:
  114.             results = function(keys, vals)
  115.         return [True, [results]]
  116.  
  117.     def rereduce(*cmd):
  118.         return reduce(*cmd, **{'rereduce': True})
  119.  
  120.     handlers = {'reset': reset, 'add_fun': add_fun, 'map_doc': map_doc,
  121.                 'reduce': reduce, 'rereduce': rereduce}
  122.  
  123.     try:
  124.         while True:
  125.             line = input.readline()
  126.             if not line:
  127.                 break
  128.             try:
  129.                 cmd = json.decode(line)
  130.                 log.debug('Processing %r', cmd)
  131.             except ValueError, e:
  132.                 log.error('Error: %s', e, exc_info=True)
  133.                 return 1
  134.             else:
  135.                 retval = handlers[cmd[0]](*cmd[1:])
  136.                 log.debug('Returning  %r', retval)
  137.                 output.write(json.encode(retval))
  138.                 output.write('\n')
  139.                 output.flush()
  140.     except KeyboardInterrupt:
  141.         return 0
  142.     except Exception, e:
  143.         log.error('Error: %s', e, exc_info=True)
  144.         return 1
  145.  
  146.  
  147. _VERSION = """%(name)s - CouchDB Python %(version)s
  148.  
  149. Copyright (C) 2007 Christopher Lenz <cmlenz@gmx.de>.
  150. """
  151.  
  152. _HELP = """Usage: %(name)s [OPTION]
  153.  
  154. The %(name)s command runs the CouchDB Python view server.
  155.  
  156. The exit status is 0 for success or 1 for failure.
  157.  
  158. Options:
  159.  
  160.   --version             display version information and exit
  161.   -h, --help            display a short help message and exit
  162.   --json-module=<name>  set the JSON module to use ('simplejson', 'cjson',
  163.                         or 'json' are supported)
  164.   --log-file=<file>     name of the file to write log messages to, or '-' to
  165.                         enable logging to the standard error stream
  166.   --debug               enable debug logging; requires --log-file to be
  167.                         specified
  168.  
  169. Report bugs via the web at <http://code.google.com/p/couchdb-python>.
  170. """
  171.  
  172.  
  173. def main():
  174.     """Command-line entry point for running the view server."""
  175.     import getopt
  176.     from couchdb import __version__ as VERSION
  177.  
  178.     try:
  179.         option_list, argument_list = getopt.gnu_getopt(
  180.             sys.argv[1:], 'h',
  181.             ['version', 'help', 'json-module=', 'debug', 'log-file=']
  182.         )
  183.  
  184.         message = None
  185.         for option, value in option_list:
  186.             if option in ('--version'):
  187.                 message = _VERSION % dict(name=os.path.basename(sys.argv[0]),
  188.                                       version=VERSION)
  189.             elif option in ('-h', '--help'):
  190.                 message = _HELP % dict(name=os.path.basename(sys.argv[0]))
  191.             elif option in ('--json-module'):
  192.                 json.use(module=value)
  193.             elif option in ('--debug'):
  194.                 log.setLevel(logging.DEBUG)
  195.             elif option in ('--log-file'):
  196.                 if value == '-':
  197.                     handler = logging.StreamHandler(sys.stderr)
  198.                     handler.setFormatter(logging.Formatter(
  199.                         ' -> [%(levelname)s] %(message)s'
  200.                     ))
  201.                 else:
  202.                     handler = logging.FileHandler(value)
  203.                     handler.setFormatter(logging.Formatter(
  204.                         '[%(asctime)s] [%(levelname)s] %(message)s'
  205.                     ))
  206.                 log.addHandler(handler)
  207.         if message:
  208.             sys.stdout.write(message)
  209.             sys.stdout.flush()
  210.             sys.exit(0)
  211.  
  212.     except getopt.GetoptError, error:
  213.         message = '%s\n\nTry `%s --help` for more information.\n' % (
  214.             str(error), os.path.basename(sys.argv[0])
  215.         )
  216.         sys.stderr.write(message)
  217.         sys.stderr.flush()
  218.         sys.exit(1)
  219.  
  220.     sys.exit(run())
  221.  
  222.  
  223. if __name__ == '__main__':
  224.     main()
  225.